home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / include / linux / seqlock.h < prev    next >
C/C++ Source or Header  |  2005-10-13  |  5KB  |  176 lines

  1. #ifndef __LINUX_SEQLOCK_H
  2. #define __LINUX_SEQLOCK_H
  3. /*
  4.  * Reader/writer consistent mechanism without starving writers. This type of
  5.  * lock for data where the reader wants a consitent set of information
  6.  * and is willing to retry if the information changes.  Readers never
  7.  * block but they may have to retry if a writer is in
  8.  * progress. Writers do not wait for readers. 
  9.  *
  10.  * This is not as cache friendly as brlock. Also, this will not work
  11.  * for data that contains pointers, because any writer could
  12.  * invalidate a pointer that a reader was following.
  13.  *
  14.  * Expected reader usage:
  15.  *     do {
  16.  *        seq = read_seqbegin(&foo);
  17.  *     ...
  18.  *      } while (read_seqretry(&foo, seq));
  19.  *
  20.  *
  21.  * On non-SMP the spin locks disappear but the writer still needs
  22.  * to increment the sequence variables because an interrupt routine could
  23.  * change the state of the data.
  24.  *
  25.  * Based on x86_64 vsyscall gettimeofday 
  26.  * by Keith Owens and Andrea Arcangeli
  27.  */
  28.  
  29. #include <linux/config.h>
  30. #include <linux/spinlock.h>
  31. #include <linux/preempt.h>
  32.  
  33. typedef struct {
  34.     unsigned sequence;
  35.     spinlock_t lock;
  36. } seqlock_t;
  37.  
  38. /*
  39.  * These macros triggered gcc-3.x compile-time problems.  We think these are
  40.  * OK now.  Be cautious.
  41.  */
  42. #define SEQLOCK_UNLOCKED { 0, SPIN_LOCK_UNLOCKED }
  43. #define seqlock_init(x)    do { *(x) = (seqlock_t) SEQLOCK_UNLOCKED; } while (0)
  44.  
  45.  
  46. /* Lock out other writers and update the count.
  47.  * Acts like a normal spin_lock/unlock.
  48.  * Don't need preempt_disable() because that is in the spin_lock already.
  49.  */
  50. static inline void write_seqlock(seqlock_t *sl)
  51. {
  52.     spin_lock(&sl->lock);
  53.     ++sl->sequence;
  54.     smp_wmb();            
  55. }    
  56.  
  57. static inline void write_sequnlock(seqlock_t *sl) 
  58. {
  59.     smp_wmb();
  60.     sl->sequence++;
  61.     spin_unlock(&sl->lock);
  62. }
  63.  
  64. static inline int write_tryseqlock(seqlock_t *sl)
  65. {
  66.     int ret = spin_trylock(&sl->lock);
  67.  
  68.     if (ret) {
  69.         ++sl->sequence;
  70.         smp_wmb();            
  71.     }
  72.     return ret;
  73. }
  74.  
  75. /* Start of read calculation -- fetch last complete writer token */
  76. static inline unsigned read_seqbegin(const seqlock_t *sl)
  77. {
  78.     unsigned ret = sl->sequence;
  79.     smp_rmb();
  80.     return ret;
  81. }
  82.  
  83. /* Test if reader processed invalid data.
  84.  * If initial values is odd, 
  85.  *    then writer had already started when section was entered
  86.  * If sequence value changed
  87.  *    then writer changed data while in section
  88.  *    
  89.  * Using xor saves one conditional branch.
  90.  */
  91. static inline int read_seqretry(const seqlock_t *sl, unsigned iv)
  92. {
  93.     smp_rmb();
  94.     return (iv & 1) | (sl->sequence ^ iv);
  95. }
  96.  
  97.  
  98. /*
  99.  * Version using sequence counter only.
  100.  * This can be used when code has its own mutex protecting the
  101.  * updating starting before the write_seqcountbeqin() and ending
  102.  * after the write_seqcount_end().
  103.  */
  104.  
  105. typedef struct seqcount {
  106.     unsigned sequence;
  107. } seqcount_t;
  108.  
  109. #define SEQCNT_ZERO { 0 }
  110. #define seqcount_init(x)    do { *(x) = (seqcount_t) SEQCNT_ZERO; } while (0)
  111.  
  112. /* Start of read using pointer to a sequence counter only.  */
  113. static inline unsigned read_seqcount_begin(const seqcount_t *s)
  114. {
  115.     unsigned ret = s->sequence;
  116.     smp_rmb();
  117.     return ret;
  118. }
  119.  
  120. /* Test if reader processed invalid data.
  121.  * Equivalent to: iv is odd or sequence number has changed.
  122.  *                (iv & 1) || (*s != iv)
  123.  * Using xor saves one conditional branch.
  124.  */
  125. static inline int read_seqcount_retry(const seqcount_t *s, unsigned iv)
  126. {
  127.     smp_rmb();
  128.     return (iv & 1) | (s->sequence ^ iv);
  129. }
  130.  
  131.  
  132. /*
  133.  * Sequence counter only version assumes that callers are using their
  134.  * own mutexing.
  135.  */
  136. static inline void write_seqcount_begin(seqcount_t *s)
  137. {
  138.     s->sequence++;
  139.     smp_wmb();
  140. }
  141.  
  142. static inline void write_seqcount_end(seqcount_t *s)
  143. {
  144.     smp_wmb();
  145.     s->sequence++;
  146. }
  147.  
  148. /*
  149.  * Possible sw/hw IRQ protected versions of the interfaces.
  150.  */
  151. #define write_seqlock_irqsave(lock, flags)                \
  152.     do { local_irq_save(flags); write_seqlock(lock); } while (0)
  153. #define write_seqlock_irq(lock)                        \
  154.     do { local_irq_disable();   write_seqlock(lock); } while (0)
  155. #define write_seqlock_bh(lock)                        \
  156.         do { local_bh_disable();    write_seqlock(lock); } while (0)
  157.  
  158. #define write_sequnlock_irqrestore(lock, flags)                \
  159.     do { write_sequnlock(lock); local_irq_restore(flags); } while(0)
  160. #define write_sequnlock_irq(lock)                    \
  161.     do { write_sequnlock(lock); local_irq_enable(); } while(0)
  162. #define write_sequnlock_bh(lock)                    \
  163.     do { write_sequnlock(lock); local_bh_enable(); } while(0)
  164.  
  165. #define read_seqbegin_irqsave(lock, flags)                \
  166.     ({ local_irq_save(flags);   read_seqbegin(lock); })
  167.  
  168. #define read_seqretry_irqrestore(lock, iv, flags)            \
  169.     ({                                \
  170.         int ret = read_seqretry(lock, iv);            \
  171.         local_irq_restore(flags);                \
  172.         ret;                            \
  173.     })
  174.  
  175. #endif /* __LINUX_SEQLOCK_H */
  176.